use chrono::Local;
use tracing::level_filters::LevelFilter;
use tracing_appender::{
    non_blocking::WorkerGuard,
    rolling::{Builder, Rotation},
};
use tracing_subscriber::{
    Layer,
    fmt::{self, format::Writer, time::FormatTime},
    layer::SubscriberExt,
    util::SubscriberInitExt,
};

struct LocalTimer;

impl FormatTime for LocalTimer {
    fn format_time(&self, w: &mut Writer<'_>) -> std::fmt::Result {
        write!(w, "{}", Local::now().format("%Y-%m-%d %H:%M:%S%.3f"))
    }
}

pub struct LogConfig {
    pub prefix: String,
    pub path: String,
    pub level: LevelFilter,
}

impl Default for LogConfig {
    fn default() -> Self {
        Self {
            prefix: String::from("app"),
            path: String::from("logs"),
            level: LevelFilter::INFO,
        }
    }
}

pub fn init_log(config: Option<LogConfig>) -> anyhow::Result<WorkerGuard> {
    let config = config.unwrap_or_default();
    let file_appender = Builder::new()
        .rotation(Rotation::DAILY)
        .filename_prefix(config.prefix)
        .build(config.path)?;

    // 非阻塞写入提升性能，并保存guard防止资源释放
    let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);

    tracing_subscriber::registry()
        .with(
            fmt::Layer::new()
                .with_timer(LocalTimer)
                .with_writer(non_blocking)
                .with_ansi(false)
                .with_filter(config.level),
        )
        .with(
            fmt::Layer::new()
                .with_timer(LocalTimer)
                .with_writer(std::io::stdout)
                .with_ansi(true)
                .with_filter(config.level),
        )
        .try_init()?;
    Ok(guard)
}
